﻿using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using System.Threading.Tasks;
using Zack.JWT;

namespace IdentityService.Domain
{
    public class IdDomainService
    {
        private readonly IIdRepository repository;
        private readonly IOptions<JWTOptions> optJWT;
        private readonly ITokenService tokenService;

        public IdDomainService(IIdRepository repository, IOptions<JWTOptions> optJWT, ITokenService tokenService)
        {
            this.repository = repository;
            this.optJWT = optJWT;
            this.tokenService = tokenService;
        }

        public async Task<(bool,int, string? Token)> LoginByUserNameAndPwdAsync(string userName, string password)
        {
            var (checkResult,errCount) = await CheckUserNameAndPwdAsync(userName, password);
            if (checkResult)
            {
                var user = await repository.FindByNameAsync(userName);
                string token = await BuildTokenAsync(user);
                return (checkResult, errCount, token);
            }
            else
            {
                return (checkResult, errCount,null);
            }
        }

        private async Task<(bool,int)> CheckUserNameAndPwdAsync(string userName, string password)
        {
            var user = await repository.FindByNameAsync(userName);
            if (user == null)
            {
                return (false,0);
            }
            return  repository.CheckForSignIn(user, password, true);
        }

        private async Task<string> BuildTokenAsync(User user)
        {
            var roles = await repository.GetRolesAsync(user);
            List<Claim> claims = new()
            {
                new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
                new Claim(ClaimTypes.Name, user.UserName)
            };
            foreach (string role in roles)
            {
                claims.Add(new Claim(ClaimTypes.Role, role));
            }
            return tokenService.BuildToken(claims, optJWT.Value);
        }
    }
}
